package com.xuecheng.base.util;

import lombok.extern.slf4j.Slf4j;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * 此文件作为视频文件处理父类，提供：<br>
 * 1、查看视频时长<br>
 * 2、校验两个视频的时长是否相等<br>
 */
@Slf4j
public class VideoUtil {

    /**
     * ffmpeg安装位置
     */
    private final String ffmpegPath;

    /**
     * 构造方法
     *
     * @param ffmpegPath ffmpeg安装位置
     */
    public VideoUtil(String ffmpegPath) {
        this.ffmpegPath = ffmpegPath;
    }

    /**
     * 检查两个视频的时长是否一致
     *
     * @param source 源视频路径
     * @param target 目标视频路径
     * @return 时长一致返回true，否则返回false
     */
    public boolean checkVideoTime(String source, String target) {
        String sourceTime = getVideoTime(source);
        String targetTime = getVideoTime(target);
        // 有一个为null，则返回false
        if (sourceTime == null || targetTime == null) return false;
        // 取出时分秒进行比较 00:00:14.18
        sourceTime = sourceTime.substring(0, sourceTime.lastIndexOf("."));
        targetTime = targetTime.substring(0, targetTime.lastIndexOf("."));
        return sourceTime.equals(targetTime);
    }

    /**
     * 获取视频时长（时:分:秒:毫秒）
     *
     * @param videoPath 视频路径
     * @return 视频时长字符串，若获取失败返回null
     */
    public String getVideoTime(String videoPath) {
        // 1. 组装命令 ffmpeg.exe -i E:\学成在线\学成在线项目—资料\视频\test.mp4
        List<String> command = new ArrayList<>();
        command.add(ffmpegPath);
        command.add("-i");
        command.add(videoPath);
        // 2. 执行命令，获取命令执行结果的视频时长
        try {
            // 2.1 执行命令
            ProcessBuilder builder = new ProcessBuilder(command);
            builder.redirectErrorStream(true);
            Process process = builder.start();
            // 2.2 等待命令执行完成并获取输出结果
            String output = waitForProcess(process);
            System.out.println("输出结果：\n" + output); // 打印输出结果：
            // 2.3 解析输出结果，获取视频时长
            int start = output.trim().indexOf("Duration: "); // D在字符串中的位置
            if (start >= 0) {
                int end = output.trim().indexOf(", start:"); // ,在字符串中的位置
                if (end >= 0) {
                    String time = output.substring(start + 10, end).trim();
                    if (!time.isEmpty()) return time;
                }
            }
        } catch (Exception e) {
            log.error("获取视频时长失败，原因为{}", e.getMessage());
        }
        return null;
    }

    /**
     * 等待进程执行完成并获取输出结果
     *
     * @param process 进程对象
     * @return 进程输出的字符串
     */
    protected String waitForProcess(Process process) {
        StringBuilder outputString = new StringBuilder();
        try (InputStream in = process.getInputStream();
             InputStream error = process.getErrorStream()) {
            boolean finished = false;
            int maxRetry = 600; // 每次休眠1秒，最长执行时间10分钟
            int retry = 0;
            while (!finished) {
                if (retry > maxRetry) return "error";
                try {
                    while (in.available() > 0)
                        outputString.append((char) in.read());
                    while (error.available() > 0)
                        outputString.append((char) error.read());
                    // 进程未结束时调用exitValue将抛出异常
                    process.exitValue();
                    finished = true;
                } catch (IllegalThreadStateException e) {
                    Thread.sleep(1000); // 休眠1秒
                    retry++;
                }
            }
        } catch (Exception e) {
            log.error("进程执行获取输出结果失败，原因为{}", e.getMessage());
        }
        return outputString.toString();
    }

    /**
     * 测试
     */
    public static void main(String[] args) {
        String ffmpegPath = "D:\\soft\\FFmpeg\\ffmpeg\\ffmpeg.exe"; // ffmpeg的安装位置
        VideoUtil videoUtil = new VideoUtil(ffmpegPath);
        String videoTime = videoUtil.getVideoTime("E:\\学成在线\\学成在线项目—资料\\upload\\视频\\test.mp4");
        System.out.println("视频时长: " + videoTime);
        boolean checkVideoTime = videoUtil.checkVideoTime("E:\\学成在线\\学成在线项目—资料\\upload\\视频\\test.mp4", "E:\\学成在线\\学成在线项目—资料\\upload\\视频\\test.avi");
        System.out.println("视频时长是否一致: " + checkVideoTime);
    }
}